package com.example.ioc.container;

import com.example.ioc.annotation.AutoWired;
import com.example.ioc.annotation.Component;

import java.io.File;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class IocContainer {
    // 存储Bean实例
    private final Map<String, Object> beans = new ConcurrentHashMap<>();

    // 包扫描路径
    private final String basePackage;

    public IocContainer(String basePackage) {
        this.basePackage = basePackage;
        try {
            // 初始化容器，扫描并实例化Bean
            init();
        } catch (Exception e) {
            throw new RuntimeException("IOC容器初始化失败", e);
        }
    }

    private void init() throws Exception {
        // 1. 扫描指定包下的所有类
        List<Class<?>> classList = scanPackages(basePackage);

        // 2. 实例化带有@Component注解的类
        instantiateBeans(classList);

        // 3. 依赖注入
        injectDependencies();
    }

    // 扫描包下的所有类
    private List<Class<?>> scanPackages(String basePackage) throws Exception {
        List<Class<?>> classList = new ArrayList<>();
        String packagePath = basePackage.replace(".", "/");
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        URL url = classLoader.getResource(packagePath);

        if (url != null && url.getProtocol().equals("file")) {
            File packageDir = new File(url.toURI());
            if (packageDir.exists() && packageDir.isDirectory()) {
                scanClasses(packageDir, basePackage, classList);
            }
        }
        return classList;
    }

    // 递归扫描类文件
    private void scanClasses(File dir, String packageName, List<Class<?>> classList) throws ClassNotFoundException {
        File[] files = dir.listFiles();
        if (files != null) {
            for (File file : files) {
                if (file.isDirectory()) {
                    scanClasses(file, packageName + "." + file.getName(), classList);
                } else if (file.getName().endsWith(".class")) {
                    String className = packageName + "." + file.getName().substring(0, file.getName().length() - 6);
                    classList.add(Class.forName(className));
                }
            }
        }
    }

    // 实例化带有@Component注解的类
    private void instantiateBeans(List<Class<?>> classList) throws Exception {
        for (Class<?> clazz : classList) {
            if (clazz.isAnnotationPresent(Component.class)) {
                Component component = clazz.getAnnotation(Component.class);
                String beanName = component.value();
                // 如果没有指定bean名称，使用类名首字母小写
                if (beanName.isEmpty()) {
                    beanName = Character.toLowerCase(clazz.getSimpleName().charAt(0)) +
                            clazz.getSimpleName().substring(1);
                }
                // 实例化并放入容器
                Object instance = clazz.getDeclaredConstructor().newInstance();
                beans.put(beanName, instance);
            }
        }
    }

    // 依赖注入
    private void injectDependencies() throws IllegalAccessException {
        for (Object bean : beans.values()) {
            Field[] fields = bean.getClass().getDeclaredFields();
            for (Field field : fields) {
                if (field.isAnnotationPresent(AutoWired.class)) {
                    field.setAccessible(true);
                    Class<?> fieldType = field.getType();
                    // 根据类型查找对应的bean
                    Object dependency = findBeanByType(fieldType);
                    if (dependency != null) {
                        field.set(bean, dependency);
                    } else {
                        throw new RuntimeException("找不到类型为 " + fieldType.getName() + " 的Bean");
                    }
                }
            }
        }
    }

    // 根据类型查找Bean
    private Object findBeanByType(Class<?> type) {
        for (Object bean : beans.values()) {
            if (type.isInstance(bean)) {
                return bean;
            }
        }
        return null;
    }

    // 获取Bean
    public Object getBean(String name) {
        return beans.get(name);
    }

    // 根据类型获取Bean
    @SuppressWarnings("unchecked")
    public <T> T getBean(Class<T> type) {
        for (Object bean : beans.values()) {
            if (type.isInstance(bean)) {
                return (T) bean;
            }
        }
        return null;
    }
}

